#include "timestampparser.h"
#include "log.h"

#include <QStringList>

namespace Wishmaster {

class TimestampParserImpl
{
public:

	TimestampParserImpl() : m_yearPos(-1), m_monthPos(-1), m_dayPos(-1),
		m_hourPos(-1), m_minPos(-1), m_secPos(-1), m_namedMonth(false)
	{

	}

	QStringList detectMonthNames(const QString& str)
	{
		QStringList list;
		list << "Jan" << "Feb" << "Mar" << "Apr" << "May" << "Jun" << "Jul" << "Aug" << "Sep" << "Oct" << "Nov" << "Dec";
		if(ciIndexOf(str, list) >= 0)
		{
			return list;
		}

		list.clear();

		list << QString::fromUtf8("Янв") <<
				QString::fromUtf8("Фев") <<
				QString::fromUtf8("Мар") <<
				QString::fromUtf8("Апр") <<
				QString::fromUtf8("Май") <<
				QString::fromUtf8("Июн") <<
				QString::fromUtf8("Июл") <<
				QString::fromUtf8("Авг") <<
				QString::fromUtf8("Сен") <<
				QString::fromUtf8("Окт") <<
				QString::fromUtf8("Ноя") <<
				QString::fromUtf8("Дек");
		if(ciIndexOf(str, list) >= 0)
			return list;

		list.clear();
		list << QString::fromUtf8("января") <<
				QString::fromUtf8("февраля") <<
				QString::fromUtf8("марта") <<
				QString::fromUtf8("апреля") <<
				QString::fromUtf8("мая") <<
				QString::fromUtf8("июня") <<
				QString::fromUtf8("июля") <<
				QString::fromUtf8("августа") <<
				QString::fromUtf8("сентября") <<
				QString::fromUtf8("октября") <<
				QString::fromUtf8("ноября") <<
				QString::fromUtf8("декабря");
		if(ciIndexOf(str, list) >= 0)
			return list;

		return QStringList();
	}

	int ciIndexOf(const QString& str, const QStringList& list)
	{
		int i = 0;
		foreach(const QString& s, list)
		{
			if(s.compare(str, Qt::CaseInsensitive) == 0)
				return i;
			i++;
		}
		return -1;
	}

private:
	QString m_pattern;
	QRegExp m_rx;
	QStringList m_monthNames;

	int m_yearPos;
	int m_monthPos;
	int m_dayPos;

	int m_hourPos;
	int m_minPos;
	int m_secPos;

	bool m_namedMonth;

	friend class TimestampParser;
};

TimestampParser::TimestampParser()
{
	m_impl = new TimestampParserImpl();
}

TimestampParser::~TimestampParser()
{
	delete m_impl;
}

void TimestampParser::setPattern(const QString& pattern)
{
	m_impl->m_pattern = pattern;
	int curpos = 0;
	int cappos = 1;
	QString regexp;
	while(curpos < pattern.length())
	{
		QChar c = pattern.at(curpos);
		if(c == 'y')
		{
			m_impl->m_yearPos = cappos++;
			regexp.append("(\\d+)");
		}
		else if(c == 'M')
		{
			m_impl->m_monthPos = cappos++;
			regexp.append("(\\d+)");
		}
		else if(c == 'd')
		{
			m_impl->m_dayPos = cappos++;
			regexp.append("(\\d+)");
		}
		else if(c == 'h')
		{
			m_impl->m_hourPos = cappos++;
			regexp.append("(\\d+)");
		}
		else if(c == 'm')
		{
			m_impl->m_minPos = cappos++;
			regexp.append("(\\d\\d)");
		}
		else if(c == 'N')
		{
			m_impl->m_monthPos = cappos++;
			regexp.append("([^\\d\\s]+)");
			m_impl->m_namedMonth = true;
		}
		else if(c == 's')
		{
			m_impl->m_secPos = cappos++;
			regexp.append("(\\d\\d)");
		}
		else
			regexp.append(c);
		curpos++;
	}
	m_impl->m_rx.setPattern(regexp);
	m_impl->m_rx.setMinimal(true);
}

QString TimestampParser::pattern() const
{
	return m_impl->m_pattern;
}

QDateTime TimestampParser::parse(const QString& str)
{
	QRegExp rx = m_impl->m_rx;
	if(rx.indexIn(str) < 0)
	{
		return QDateTime();
	}

	//log(llDebug, "%s/%s", qPrintable(str), qPrintable(rx.pattern()));
	int year = rx.cap(m_impl->m_yearPos).toUInt();
	if(year < 100)
		year += 2000; // Will be invalid in 2100, but whatever...
	int month = 0;
	QString monthString = rx.cap(m_impl->m_monthPos);

	if(!m_impl->m_namedMonth)
		month = monthString.toUInt();
	else
	{
		if(m_impl->m_monthNames.isEmpty())
		{
			m_impl->m_monthNames = m_impl->detectMonthNames(monthString);
		}
		month = m_impl->ciIndexOf(monthString, m_impl->m_monthNames) + 1;
	}
	int day = rx.cap(m_impl->m_dayPos).toUInt();

	int hour = rx.cap(m_impl->m_hourPos).toUInt();
	int min = rx.cap(m_impl->m_minPos).toUInt();
	int sec = rx.cap(m_impl->m_secPos).toUInt();

	//log(llDebug, "%d/%d/%d %d/%d/%d", year, month, day, hour, min, sec);

	return QDateTime(QDate(year, month, day), QTime(hour, min, sec));
}

TimestampParser TimestampParser::operator=(const TimestampParser& parser)
{
	m_impl = new TimestampParserImpl(*parser.m_impl);
	return *this;
}

} // namespace Wishmaster
